package org.dreamwork.tools.network.bridge.client.fx.controllers;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import javafx.geometry.Dimension2D;
import netscape.javascript.JSObject;
import org.dreamwork.network.service.ServiceFactory;
import org.dreamwork.tools.network.bridge.client.data.Proxy;
import org.dreamwork.tools.network.bridge.client.data.Server;
import org.dreamwork.tools.network.bridge.client.services.IBroadcastService;
import org.dreamwork.tools.network.bridge.client.services.IClientMonitorService;
import org.dreamwork.tools.network.bridge.client.services.IClientService;
import org.dreamwork.util.StringUtil;

import java.lang.reflect.Type;
import java.util.*;

import static org.dreamwork.tools.network.bridge.client.Keys.CAT_SESSION;
import static org.dreamwork.tools.network.bridge.client.concurrent.Const.Action.ACT_TUNNELS;
import static org.dreamwork.tools.network.bridge.client.concurrent.Const.MessageType.*;

public class TunnelWebPage extends AbstractWebPage {
    private String proxyId;
    private final IClientService service = ServiceFactory.get (IClientService.class);

    TunnelWebPage () {
        super ("web-ui/tunnel.html");
        setResizable (false);
    }

    TunnelWebPage (String proxyId) {
        this ();
        this.proxyId = proxyId;
    }

    @Override
    protected Object performAction (String action, Object params) {
        Gson g = new Gson ();
        IBroadcastService broadcaster = ServiceFactory.get (IBroadcastService.class);
        if (!StringUtil.isEmpty (action)) switch (action) {
            case "check-tunnel-name":
                if (!(params instanceof String)) {
                    return true;
                } else {
                    String name = (String) params;
                    return !service.isProxyPresent (name);
                }

            case "check-tunnel-port":
                if (!(params instanceof String)) {
                    return true;
                } else {
                    Proxy p = g.fromJson ((String) params, Proxy.class);
                    return !service.isProxyPresent (p.server, p.servicePort);
                }

            case "save":
                if (!(params instanceof String)) {
                    return null;
                } else {
                    Proxy p = g.fromJson ((String) params, Proxy.class);
                    if (StringUtil.isEmpty (p.id)) {
                        // create a new proxy
                        p.id = StringUtil.uuid ();
                        service.save (p);
                        broadcaster.broadcast (ACT_TUNNELS, MT_TUNNEL_ADD, p);
                    } else {
                        // update the proxy
                        service.update (p);
                        broadcaster.broadcast (ACT_TUNNELS, MT_TUNNEL_UPDATE, p);
                        // notify the proxy has updated to org.dreamwork.tools.network.bridge.client.ManagerClient
                        broadcaster.broadcast (CAT_SESSION, 1, p);
                    }

                    if (stage != null) {
                        stage.close ();
                    }
                    return proxyToMap (p);
                }

            case "delete":
                if (!(params instanceof String)) {
                    return false;
                }
                boolean success = deleteProxy ((String) params);
                broadcaster.broadcast (ACT_TUNNELS, MT_TUNNEL_DELETE, params);
                return success;

/*
            case "connect":
                connect (proxyId);
                return null;

            case "disconnect":
                disconnect (proxyId);
                return null;
*/
        }
        return null;
    }

    @Override
    protected void onPageLoaded (JSObject window) {
        background (() -> {
            Map<String, Object> map = new HashMap<> ();
            IClientService service = ServiceFactory.get (IClientService.class);
            {
                List<Server> servers = service.getServers ();
                if (servers != null && !servers.isEmpty ()) {
                    List<String> names   = new ArrayList<> (servers.size ());
                    servers.forEach (e->names.add (e.getName ()));
                    map.put ("servers", names);
                }
            }

            if (!StringUtil.isEmpty (proxyId)) {
                Proxy proxy = service.getById (Proxy.class, proxyId);
                if (proxy != null) {
                    map.put ("tunnel", proxyToMap (proxy));
                }
            }

            bridge.firePageLoaded (new Gson ().toJson (map));
        });
    }

    @Override
    public Dimension2D getSize () {
        return new Dimension2D (450, 394);
    }

    private boolean deleteProxy (String id) {
        if (id.equals (proxyId)) {
            Proxy p = service.getById (Proxy.class, id);
            if (p != null) {
                IClientMonitorService monitor = ServiceFactory.get (IClientMonitorService.class);
                if (monitor.containsClient (p.name)) {
                    try {
                        monitor.getClient (p.name).detach ();
                    } catch (Exception ex) {
                        ex.printStackTrace ();
                        return false;
                    }
                }
                service.delete (p);
            }
        }
        return false;
    }

/*
    private void connect (String proxyId) {

    }

    private void disconnect (String proxyId) {

    }
*/

    private Map<String, Object> proxyToMap (Proxy proxy) {
        Type type = new TypeToken<Map<String, Object>> () {}.getType ();
        Gson g = new Gson ();
        String content = g.toJson (proxy);
        Map<String, Object> map = g.fromJson (content, type);
        IClientMonitorService monitor = ServiceFactory.get (IClientMonitorService.class);
        map.put ("connected", monitor.containsClient (proxy.name));
        return map;
    }
}
